package com.slofzx.nuoda.evaluation.version.service.impl;

import com.slofzx.nuoda.common.enums.CommonResultEnum;
import com.slofzx.nuoda.common.enums.ServiceResult;
import com.slofzx.nuoda.common.exception.ServiceException;
import com.slofzx.nuoda.common.service.impl.BaseServiceImpl;
import com.slofzx.nuoda.common.util.DataConvertUtil;
import com.slofzx.nuoda.common.util.IdGen;
import com.slofzx.nuoda.common.vo.SysUserVO;
import com.slofzx.nuoda.evaluation.core.enums.ComputeVersionMarkEnum;
import com.slofzx.nuoda.evaluation.enums.ComputeVersionTypeEnum;
import com.slofzx.nuoda.evaluation.model.feign.ModelConfigClient;
import com.slofzx.nuoda.evaluation.param.dto.ProjectCostDataDTO;
import com.slofzx.nuoda.evaluation.param.service.*;
import com.slofzx.nuoda.evaluation.param.vo.*;
import com.slofzx.nuoda.evaluation.project.dto.*;
import com.slofzx.nuoda.evaluation.project.enums.BatchQualityEnum;
import com.slofzx.nuoda.evaluation.project.enums.BatchStateEnum;
import com.slofzx.nuoda.evaluation.project.enums.EvaluationMethodEnum;
import com.slofzx.nuoda.evaluation.project.service.*;
import com.slofzx.nuoda.evaluation.project.util.BusiUtil;
import com.slofzx.nuoda.evaluation.project.vo.*;
import com.slofzx.nuoda.evaluation.ref.init.ModelInputItemLoader;
import com.slofzx.nuoda.evaluation.ref.service.ModelExportRefService;
import com.slofzx.nuoda.evaluation.ref.service.ModelParamRefService;
import com.slofzx.nuoda.evaluation.ref.vo.ModelParamRefVO;
import com.slofzx.nuoda.evaluation.version.builder.ComputeInputDataBuilder;
import com.slofzx.nuoda.evaluation.version.dto.BatchComputeDTO;
import com.slofzx.nuoda.evaluation.version.dto.ComputeVersionDTO;
import com.slofzx.nuoda.evaluation.version.service.BatchComputeService;
import com.slofzx.nuoda.evaluation.version.service.ComputeVersionService;
import com.slofzx.nuoda.evaluation.model.vo.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 评价任务批量计算业务逻辑实现
 *
 * @author sunfuyong
 */
@Service
public class BatchComputeServiceImpl extends BaseServiceImpl implements BatchComputeService {
    @Autowired
    private ProjectInfoService projectInfoService;
    @Autowired
    private ProjectYearDataService projectYearDataService;
    @Autowired
    private ProjectCostDataService projectCostDataService;

    @Autowired
    private ModelParamRefService modelParamRefService;

    @Autowired
    private CommonUnitCostService commonUnitCostService;
    @Autowired
    private CommonFixedService commonFixedService;
    @Autowired
    private CommonBaseIrrService commonBaseIrrService;
    @Autowired
    private CommonYearRelatedService commonYearRelatedService;

    @Autowired
    private ModelExportRefService modelExportRefService;
    @Autowired
    private BatchInfoService batchInfoService;
    @Autowired
    private PlanInfoService planInfoService;
    @Autowired
    private BatchCommonDataService batchCommonDataService;
    @Autowired
    private ComputeVersionService computeVersionService;


    private static final String VERSION_PREFIX = "评价版本V";

    @Autowired
    private ModelConfigClient modelConfigClient;

//    @Autowired
//    private ProjectReportService projectReportService;

//    @Autowired
//    private ProjectReportDetailService projectReportDetailService;
    //临时写法，方便修正处理历史数据
//    @Resource
//    private ProjectReportDetailDAO projectReportDetailDAO;

    @Autowired
    private ModelInputItemLoader modelInputItemLoader;


    @Transactional
    public ServiceResult computeBatchResult(BatchComputeDTO dto) {
        String batchId = dto.getBatchId();
        BatchQualityEnum batchQualityEnum = BusiUtil.getEnumById(dto.getQuality(),BatchQualityEnum.class);
        ComputeInfoDataVO computeInfoDataVO = null;
        if (BatchQualityEnum.PLAN == batchQualityEnum) {
            computeInfoDataVO = planInfoService.queryById(batchId);
        } else {
            computeInfoDataVO = batchInfoService.queryById(batchId);
        }

        if (computeInfoDataVO == null) {
            return CommonResultEnum.NOT_EXIST;
        }
        if (BatchStateEnum.getEnum(computeInfoDataVO.getState()) == BatchStateEnum.PUBLISH) {
            throw new ServiceException("该任务已锁定，无法计算", "该任务已锁定，无法计算", computeInfoDataVO);
        }
        ModelConfigVO modelConfigVO = modelConfigClient.queryById(computeInfoDataVO.getModelId(),"sys").getData();
        if(modelConfigVO == null) {
            throw new ServiceException("获取评价模型信息失败，无法计算", "获取评价模型信息失败，无法计算", dto);
        }
        SysUserVO user = getUser();
        if (BatchQualityEnum.OUT_PUT== batchQualityEnum && user.isAdmin() == false && false == user.getId().equals(computeInfoDataVO.getCreateUser())) {
            //如果不是管理员，非本人无法计算项目
            return CommonResultEnum.PERMISSION_DENY;
        }

        //查询任务相关项目列表
        ProjectInfoDTO projectInfoDTO = new ProjectInfoDTO();
        projectInfoDTO.setBatchId(batchId);
        projectInfoDTO.setIdList(dto.getFilterProjectSet());
        List<ProjectInfoVO> projectList = projectInfoService.queryList(projectInfoDTO);
        if(projectList==null||projectList.isEmpty()) {
            throw new ServiceException("无项目数据，无法计算",batchId+"无项目数据，无法计算",dto);
        }
        String commonParamVersionId = computeInfoDataVO.getParamVersion();
        //查询单位成本数据
//        List<CommonUnitCostVO> commonUnitCostList = commonUnitCostService.queryListByVersion(commonParamVersionId);
//        //转换为单位->成本数据 集合备用
//        Map<String, CommonUnitCostVO> commonUnitCostMap = new HashMap<>();
//        for (CommonUnitCostVO item : commonUnitCostList) {
//            commonUnitCostMap.put(item.getCompanyId(), item);
//        }
//        //查询固定参数数据
//        CommonFixedVO commonFixedVO = commonFixedService.queryByVersion(commonParamVersionId);
        //查询基准收益率
        List<CommonBaseIrrVO> commonBaseIrrList = commonBaseIrrService.queryListByVersion(commonParamVersionId);
        Map<String, CommonBaseIrrVO> baseIrrVOMap = new HashMap<>();
        for (CommonBaseIrrVO item : commonBaseIrrList) {
            baseIrrVOMap.put(item.getPoolType(), item);
        }
        //查询年度相关公共参数
        List<CommonYearRelatedVO> commonYearRelatedList = commonYearRelatedService.queryListByVersion(commonParamVersionId);

        //查询评价任务公共参数
        BatchCommonDataDTO batchCommonDataDTO = new BatchCommonDataDTO();
        batchCommonDataDTO.setBatchId(batchId);
        List<BatchCommonDataVO> batchCommonDataList = batchCommonDataService.queryList(batchCommonDataDTO);
        computeInfoDataVO.setYearDataList(batchCommonDataList);

        //查询项目年度数据
        ProjectYearDataDTO projectYearDataDTO = new ProjectYearDataDTO();
        projectYearDataDTO.setProjectIdList(dto.getFilterProjectSet());
        List<ProjectYearDataVO> projectYearDataList = projectYearDataService.queryList(projectYearDataDTO);
        Map<String, List<ProjectYearDataVO>> projectYearDataListMap = projectYearDataList.stream().collect(Collectors.groupingBy(ProjectYearDataVO::getProjectId));
        final Set<String> projectIdSet = projectList.stream().map(ProjectInfoVO::getId).collect(Collectors.toSet());
        final ProjectCostDataDTO projectCostDataDTO = new ProjectCostDataDTO();
        projectCostDataDTO.setFilterIdSet(projectIdSet);
        final List<ProjectCostDataVO> projectCostDataVOS = projectCostDataService.queryList(projectCostDataDTO);
        final Map<String, ProjectCostDataVO> projectCostDataVOMap = projectCostDataVOS.stream().collect(Collectors.toMap(ProjectCostDataVO::getId, Function.identity(), (v1, v2) -> v1));
        //获取输入数据映射关系
        List<ModelParamRefVO> refVOList = modelParamRefService.queryListByModel(computeInfoDataVO.getModelId());
        if (refVOList == null || refVOList.isEmpty()) {
            throw new ServiceException("未配置评价模型录入参数映射，无法计算", "未配置评价模型录入参数映射，无法计算 model:" + computeInfoDataVO.getModelId(), computeInfoDataVO);
        }


        //记录全部的评价版本信息
        List<ComputeVersionDTO> totalVersionList = new ArrayList<>();
        if (ComputeVersionTypeEnum.getEnum(dto.getType()) == null) {
            dto.setType(ComputeVersionTypeEnum.DEFAULT.getId());
        }
        ComputeVersionDTO batchComputeVersionDTO = new ComputeVersionDTO();
        batchComputeVersionDTO.setBatchId(batchId);
        batchComputeVersionDTO.setCutoff(computeInfoDataVO.isCutoff());
        Integer maxVersion = computeVersionService.queryMaxVersionNum(batchId);
        maxVersion = DataConvertUtil.parse2Int(maxVersion, 0) + 1;
        batchComputeVersionDTO.setId(IdGen.uuid());
        batchComputeVersionDTO.setModelId(computeInfoDataVO.getModelId());
        batchComputeVersionDTO.setVersionNum(maxVersion);
        batchComputeVersionDTO.setName(VERSION_PREFIX + maxVersion);
        batchComputeVersionDTO.setProjectId(projectInfoDTO.getId());
        batchComputeVersionDTO.setCutoff(computeInfoDataVO.isCutoff());
        batchComputeVersionDTO.setBuildYearCount(1);
        batchComputeVersionDTO.setMark(ComputeVersionMarkEnum.RESULT.getId());
        batchComputeVersionDTO.setType(ComputeVersionTypeEnum.DEFAULT.getId());
        batchComputeVersionDTO.setParamVersion(commonParamVersionId);
        totalVersionList.add(batchComputeVersionDTO);
        Map<String, ComputeVersionDTO> projectComputeVersionMap = new HashMap<>();
        boolean isPlan = BatchQualityEnum.PLAN == batchQualityEnum;
        //记录所有项目最早开始评价年份与最晚结束评价年份
        Integer minYear = null, maxYear = null;
        for (ProjectInfoVO item : projectList) {
            if (item.getYear() == null) {
                item.setYear(computeInfoDataVO.getYear());
            }
            int evaBeginYear = DataConvertUtil.parse2Int(item.getYear());
            int evaEndYear = evaBeginYear + DataConvertUtil.parse2Int(item.getEvaluationPeriod()) - 1;
            if (minYear == null) {
                minYear = evaBeginYear;
            } else if (minYear > evaBeginYear) {
                minYear = evaBeginYear;
            }
            if (maxYear == null) {
                maxYear = evaEndYear;
            } else if (maxYear < evaEndYear) {
                maxYear = evaEndYear;
            }
            CommonParamDataVO commonParamDataVO = new CommonParamDataVO();
          //  commonParamDataVO.setCommonFixed(commonFixedVO);
            commonParamDataVO.setVersionId(commonParamVersionId);
          //  commonParamDataVO.setCommonUnitCost(commonUnitCostMap.get(item.getBuildOffice()));

            commonParamDataVO.setCommonYearRelatedList(commonYearRelatedList);

            ComputeVersionDTO itemVersionDTO = new ComputeVersionDTO();
            if (baseIrrVOMap.get(item.getPoolType()) != null) {
                final Double baseIrr = baseIrrVOMap.get(item.getPoolType()).getValue();
                commonParamDataVO.setBaseIrr(baseIrr);
                itemVersionDTO.setBaseIrr(baseIrr);
            }
            Double totalInvest = DataConvertUtil.parse2Double(item.getDrillExtractInvest()) +
                    DataConvertUtil.parse2Double(item.getOtherInvest()) +
                    DataConvertUtil.parse2Double(item.getGroundInvest());
            itemVersionDTO.setTotalInvest(totalInvest);
            itemVersionDTO.setBatchId(batchId);
            itemVersionDTO.setProjectId(item.getId());
            itemVersionDTO.setParentId(batchComputeVersionDTO.getId());

            itemVersionDTO.setModelId(batchComputeVersionDTO.getModelId());
            itemVersionDTO.setVersionNum(batchComputeVersionDTO.getVersionNum());
            itemVersionDTO.setName(item.getName());
            itemVersionDTO.setCutoff(computeInfoDataVO.isCutoff());
            itemVersionDTO.setBuildYearCount(1);
            itemVersionDTO.setType(ComputeVersionTypeEnum.DEFAULT.getId());
            itemVersionDTO.setCalculateYearStart(evaBeginYear);
            itemVersionDTO.setCalculateYearEnd(evaEndYear);

            ComputeInputDataBuilder inputDataBuilder = new ComputeInputDataBuilder();
            inputDataBuilder.modelInputItemList(modelInputItemLoader.getDataList());
            if (MapUtils.isNotEmpty(projectCostDataVOMap)) {
                item.setProjectCostData(projectCostDataVOMap.get(item.getId()));
            }
            inputDataBuilder.evaluateBeginYear(evaBeginYear);
            inputDataBuilder.evaluateEndYear(evaEndYear);
            inputDataBuilder.commonParamData(commonParamDataVO);
            inputDataBuilder.modelParamRefList(refVOList);
            item.setYearDataList(projectYearDataListMap.get(item.getId()));
            inputDataBuilder.projectDetailData(item);
            inputDataBuilder.computeInfoDataVO(computeInfoDataVO);
            inputDataBuilder.modelConfig(modelConfigVO);
            itemVersionDTO.setDataMap(inputDataBuilder.build());
            itemVersionDTO.setParamVersion(commonParamVersionId);
            projectComputeVersionMap.put(item.getId(), itemVersionDTO);
            // 每次批量计算完 方案任务的常规项目默认为最终版，如果没有则不标记
            if (isPlan && EvaluationMethodEnum.CONVENTIONAL.getId().equals(item.getEvaluationMethod())) {
                itemVersionDTO.setUltimate(true);
            }
            totalVersionList.add(itemVersionDTO);
        }
        batchComputeVersionDTO.setCalculateYearStart(minYear);
        batchComputeVersionDTO.setCalculateYearEnd(maxYear);
        // 取消项目的最终版本标记
        if (isPlan) {
            projectInfoService.cancelUltimate(batchId);
        }
        computeVersionService.batchComputeProjectResult(modelConfigVO,totalVersionList);
        dto.setId(batchComputeVersionDTO.getId());
        if (isPlan) {
            final PlanInfoDTO planInfoDTO = new PlanInfoDTO();
            planInfoDTO.setId(batchId);
            planInfoDTO.setVersionId(batchComputeVersionDTO.getId());
            planInfoDTO.setCutoff(computeInfoDataVO.isCutoff());
            planInfoService.update(planInfoDTO);
        } else {
            final BatchInfoDTO batchInfoDTO = new BatchInfoDTO();
            batchInfoDTO.setId(batchId);
            batchInfoDTO.setVersionId(batchComputeVersionDTO.getId());
            batchInfoDTO.setCutoff(computeInfoDataVO.isCutoff());
            batchInfoService.update(batchInfoDTO);
        }
        return CommonResultEnum.SUCCESS;
    }




//    @Transactional
//    @Override
//    public ServiceResult extractResultItem(String reportItem) {
//        SysUserVO user = getUser();
//        if(!user.isAdmin()){
//            return CommonResultEnum.PERMISSION_DENY;
//        }
//        ProjectReportItemEnum itemEnum = ProjectReportItemEnum.getEnum(reportItem);
//        if(itemEnum == null) {
//            return CommonResultEnum.NOT_EXIST;
//        }
//        List<ProjectReportVO> reportList = projectReportService.queryList(new ProjectReportDTO());
//        List<ProjectReportDetail> reportDetailList = projectReportDetailDAO.queryList(new ProjectReportDetailYearDTO());
//        Map<String,ProjectReportDetail> reportDetailMap = new HashMap<>();
//        for(ProjectReportDetail item:reportDetailList) {
//            reportDetailMap.put(item.getReportId()+"#"+item.getMark(),item);
//        }
//        ComputeDetailDataDTO detailDataDTO = new ComputeDetailDataDTO();
//        detailDataDTO.setFilterMarkSet(new HashSet<String>(){{
//            add(ProjectComputeDataMarkEnum.REAL_FORECAST_PRICE.getId());
//            add(ProjectComputeDataMarkEnum.FEA_DESIGN.getId());
//        }});
//        List<ComputeDetailDataVO> detailList = computeDetailDataService.queryList(detailDataDTO);
//        Map<String,ComputeDetailDataVO> detailDataMap = new HashMap<>();
//        for(ComputeDetailDataVO item:detailList) {
//            detailDataMap.put(item.getSourceId()+"#"+item.getMark(),item);
//        }
//
//        Map<String, ModelExportRefVO> modelExportRefVOMap = modelExportRefService.queryModelExportRefMap();
//        ModelExportRefVO unitCostRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.UNIT_TOTAL_COST.getId());
//        ModelExportRefVO totalCostRefVO = modelExportRefVOMap.get(ProjectReportItemEnum.TOTAL_COST.getId());
//        for(ProjectReportVO report:reportList) {
//            ComputeResultVO realData = JSON.parseObject(detailDataMap.get(report.getId()+"#"+ProjectComputeDataMarkEnum.REAL_FORECAST_PRICE.getId()).getDetail(),ComputeResultVO.class);
//            ComputeDetailDataVO feaDetailData = detailDataMap.get(report.getId()+"#"+ProjectComputeDataMarkEnum.FEA_DESIGN.getId());
//            ComputeResultVO feaData = null;
//            if(feaDetailData!=null) {
//                feaData = JSON.parseObject(feaDetailData.getDetail(),ComputeResultVO.class);
//            }else {
//                //查询可研上传文件
//                List<FileVO> fileList = fileInfoClient.findFileList(FileSourceEnum.PROJECT.getId(), report.getProjectId(), "fea_eva_result").getData();
//                if (fileList != null && fileList.size() > 0) {
//                    //设置前评数据预览
//                    String fileId = fileList.get(0).getId();
//                    feaData = parsePreEvaluationFileResult(fileId);
//                }
//            }
//            if(realData!=null) {
//                ProjectReportDetail reportDetail = reportDetailMap.get(report.getId()+"#"+ProjectExtendDataMarkEnum.REAL.getId());
//                reportDetail.setUnitTotalCost(DoubleUtil.getScale(DataConvertUtil.parse2Double(realData.getGroupDataMap().get(unitCostRefVO.getSourceId())),2));
//                reportDetail.setTotalCost(DoubleUtil.getScale(DataConvertUtil.parse2Double(realData.getGroupDataMap().get(totalCostRefVO.getSourceId())),2));
//                projectReportDetailDAO.updateById(reportDetail);
//            }
//            if(feaData!=null) {
//                ProjectReportDetail reportDetail = reportDetailMap.get(report.getId()+"#"+ProjectExtendDataMarkEnum.FEASIBILITY.getId());
//                reportDetail.setUnitTotalCost(DoubleUtil.getScale(DataConvertUtil.parse2Double(feaData.getGroupDataMap().get(unitCostRefVO.getSourceId())),2));
//                reportDetail.setTotalCost(DoubleUtil.getScale(DataConvertUtil.parse2Double(feaData.getGroupDataMap().get(totalCostRefVO.getSourceId())),2));
//                projectReportDetailDAO.updateById(reportDetail);
//            }
//
//        }
//
//        return CommonResultEnum.SUCCESS;
//    }
//
//    @Transactional
//    @Override
//    public ServiceResult extractComputeResultResult(QueryDTO dto) {
//        SysUserVO user = getUser();
//        if(!user.isAdmin()){
//            return CommonResultEnum.PERMISSION_DENY;
//        }
//        List<ProjectReportVO> reportList = projectReportService.queryList(new ProjectReportDTO());
//        Map<String,ProjectReportVO> projectReportVOMap = new HashMap<>();
//        for(ProjectReportVO item:reportList) {
//            projectReportVOMap.put(item.getId(),item);
//        }
////        List<ProjectReportDetail> reportDetailList = projectReportDetailDAO.queryList(new ProjectReportDetailYearDTO());
////        Map<String,ProjectReportDetail> reportDetailMap = new HashMap<>();
////        for(ProjectReportDetail item:reportDetailList) {
////            reportDetailMap.put(item.getReportId()+"#"+item.getMark(),item);
////        }
////        ComputeDetailDataDTO detailDataDTO = new ComputeDetailDataDTO();
////        detailDataDTO.setFilterMarkSet(new HashSet<String>(){{
////            add(ProjectComputeDataMarkEnum.REAL_FORECAST_PRICE.getId());
////            add(ProjectComputeDataMarkEnum.FEA_DESIGN.getId());
////        }});
////        List<ComputeDetailDataVO> detailList = computeDetailDataService.queryList(detailDataDTO);
//        Map<String,ComputeDetailDataVO> detailDataMap = new HashMap<>();
//        List<ProjectReportDetailSum> dataList = new ArrayList<>();
//        Map<String, ModelExportRefVO> modelExportRefVOMap = modelExportRefService.queryModelExportRefMap();
//        logger.info("共 {} 条报告，开始提取数据...",reportList.size());
//        int index = 1;
//        for(ProjectReportVO reportVO:reportList) {
//            ComputeDetailDataDTO dataDTO = new ComputeDetailDataDTO();
//            dataDTO.setSourceType("project");
//            dataDTO.setSourceId(reportVO.getId());
//            logger.info("开始提取第 {} 条报告数据，还剩 {} 条",index,reportList.size()-index);
//            index++;
//            List<ComputeDetailDataVO> detailList = computeDetailDataService.queryList(dataDTO);
//            if (detailList == null || detailList.isEmpty()) {
//                continue;
//            }
//            for (ComputeDetailDataVO item : detailList) {
//                ComputeResultVO computeResultVO = JSON.parseObject(item.getDetail(), ComputeResultVO.class);
//                for (ProjectReportItemEnum reportItemEnum : ProjectReportItemEnum.values()) {
//                    ModelExportRefVO refVO = modelExportRefVOMap.get(reportItemEnum.getId());
//                    if (refVO == null) {
//                        continue;
//                    }
//                    ProjectReportDetailSum entity = new ProjectReportDetailSum();
//                    entity.setId(IdGen.uuid());
//                    entity.setCreateTime(new Date());
//                    entity.setCreateUser(user.getId());
//                    entity.setItem(reportItemEnum.getId());
//                    entity.setReportId(item.getSourceId());
//                    entity.setProjectId(reportVO.getProjectId());
//                    entity.setMark(item.getMark());
//                    Object value = computeResultVO.getGroupDataMap().get(refVO.getSourceId());
//                    if (value == null) {
//                        continue;
//                    }
//                    entity.setValue(DataConvertUtil.parse2Double(value));
//                    dataList.add(entity);
//                }
//            }
//        }
//        logger.info("共 {} 条报告，数据提取完成，准备存储，共 {} 条数据",reportList.size(),dataList.size());
//        projectReportDetailSumDAO.delete(new LambdaQueryWrapper<ProjectReportDetailSum>().in(ProjectReportDetailSum::getReportId,projectReportVOMap.keySet()));
//        if(dataList.size()>0) {
//            saveBatch(dataList,projectReportDetailSumDAO,ProjectReportDetailSum.class);
//        }
//        logger.info("共 {} 条报告，数据提取存储完成，共 {} 条数据",reportList.size(),dataList.size());
//        return CommonResultEnum.SUCCESS;
//    }

}
